#include "StdAfx.h"
#include "sa_TwParticle.h"


struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR; FLOAT U, V;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
struct GRIDVERTEX {D3DXVECTOR3 position; DWORD color;};
#define GRIDFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
LPDIRECT3DVERTEXBUFFER9 t_buffer ;    // the pointer to the particle's vertex buffer
// texture declarations
LPDIRECT3DTEXTURE9 texture;

sa_TwParticle::sa_TwParticle(void)
{
}

sa_TwParticle::~sa_TwParticle(void)
{
}
void sa_TwParticle::InitGraphics()
{
	// load the texture we will use
	D3DXCreateTextureFromFile(g_Render->GetDevice(),
		(LPCSTR)"fire.png",
		&texture);

	// create the vertices using the CUSTOMVERTEX
	struct CUSTOMVERTEX t_vert[] =
	{
		{-1.0f, 1.0f, 0.0f, D3DCOLOR_XRGB(118, 89, 55), 1, 0,},
		{-1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(118, 89, 55), 0, 0,},
		{1.0f, 1.0f, 0.0f, D3DCOLOR_XRGB(118, 89, 55), 1, 1,},
		{1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(118, 89, 55), 0, 1,},
	};

	// create a vertex buffer interface called t_buffer
	g_Render->GetDevice()->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX),
		0,
		CUSTOMFVF,
		D3DPOOL_MANAGED,
		&t_buffer,
		NULL);

	VOID* pVoid;    // a void pointer

	// lock t_buffer and load the vertices into it
	t_buffer->Lock(0, 0, (void**)&pVoid, 0);
	memcpy(pVoid, t_vert, sizeof(t_vert));
	t_buffer->Unlock();
	InitRenderState();
}

void sa_TwParticle::InitRenderState()
{
	g_Render->GetDevice()->SetRenderState(D3DRS_LIGHTING, FALSE);
	g_Render->GetDevice()->SetRenderState(D3DRS_ZENABLE, TRUE);

	g_Render->GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);    // turn on the color blending
	g_Render->GetDevice()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVDESTCOLOR);    // set source factor
	g_Render->GetDevice()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);    // set dest factor
	g_Render->GetDevice()->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);    // set the operation

}

void sa_TwParticle::InitLight()
{

}

void sa_TwParticle::Update()
{

}

void sa_TwParticle::Render()
{
	g_Render->GetDevice()->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
	g_Render->GetDevice()->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	g_Render->GetDevice()->BeginScene();

	// calculate the camera position
	static float index = 0.0f; index+=0.01f;
	camx = cos(index) * 5.0f; camy = 2.0f; camz = sin(index) * 5.0f;

	// set the view transform
	D3DXMATRIX matView;
	D3DXMatrixLookAtLH(&matView,
		&D3DXVECTOR3 (camx, camy, camz),
		&D3DXVECTOR3 (0.0f, 0.0f, 0.0f),
		&D3DXVECTOR3 (0.0f, 1.0f, 0.0f));
	g_Render->GetDevice()->SetTransform(D3DTS_VIEW, &matView);

	// set the projection transform
	D3DXMATRIX matProjection;
	D3DXMatrixPerspectiveFovLH(&matProjection,
		D3DXToRadian(45),
		(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT,
		1.0f,
		100.0f);
	g_Render->GetDevice()->SetTransform(D3DTS_PROJECTION, &matProjection);

	// render the grid
	g_Render->GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	render_grid();

	// calculate elapsed time
	static DWORD starting_point = GetTickCount(), time;
	time = GetTickCount() - starting_point;
	starting_point = GetTickCount();

	// prepare particle for rendering
	particle.run_particle(time / 1000.0f);
	particle.set_particle(camx, camy, camz);

	g_Render->GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	particle.render_particle();

	g_Render->GetDevice()->EndScene();

	g_Render->GetDevice()->Present(NULL, NULL, NULL, NULL);


}

void sa_TwParticle::Clear()
{
	t_buffer->Release();    // close and release the particle vertex buffer
	g_buffer->Release();    // close and release the grid vertex buffer
	texture->Release();    // close and release the texture

}


// this function renders the grid
void sa_TwParticle::render_grid()
{
	static bool InitNeeded = true;
	static int GridSize = 10;
	static D3DXMATRIX matIdentity;

	g_Render->GetDevice()->SetFVF(GRIDFVF);

	if(InitNeeded)
	{
		g_Render->GetDevice()->CreateVertexBuffer(sizeof(GRIDVERTEX) * GridSize * 9,
			0,
			GRIDFVF,
			D3DPOOL_MANAGED,
			&g_buffer,
			0);

		GRIDVERTEX* pGridData = 0;
		g_buffer->Lock(0, 0, (void**)&pGridData, 0);

		int index = 0;
		for(; index <= GridSize * 4 + 1; index++)
		{
			float x = (index % 2) ? GridSize : -GridSize;
			float y = 0.0f;
			float z = index / 2 - GridSize;

			pGridData[index].position = D3DXVECTOR3(x, y, z);
			pGridData[index].color = D3DXCOLOR(0.4f, 0.4f, 0.4f, 1.0f);
		}

		for(; index <= GridSize * 8 + 4; index++)
		{
			static int half = index;
			float x = (index - half) / 2 - GridSize;
			float y = 0.0f;
			float z = (index % 2) ? -GridSize : GridSize;

			pGridData[index].position = D3DXVECTOR3(x, y, z);
			pGridData[index].color = D3DXCOLOR(0.4f, 0.4f, 0.4f, 1.0f);
		}

		g_buffer->Unlock();

		D3DXMatrixIdentity(&matIdentity);
		InitNeeded = false;
	}

	g_Render->GetDevice()->SetTransform(D3DTS_WORLD, &matIdentity);
	g_Render->GetDevice()->SetStreamSource(0, g_buffer, 0, sizeof(GRIDVERTEX));
	g_Render->GetDevice()->SetTexture(0, NULL);
	g_Render->GetDevice()->DrawPrimitive(D3DPT_LINELIST, 0, GridSize * 4 + 2);

	return;
}



// this is the function that positions, rotates, scales and renders the particle
void PARTICLE::set_particle(float camx, float camy, float camz)
{
	// Before setting the world transform, do the intense mathematics!
	// a. Calculate the Differences
	static float difx, dify, difz;
	difx = camx - position.x;
	dify = camy - position.y;
	difz = camz - position.z;
	// ooh, intense!

	// b. Calculate the Distances
	static float FlatDist, TotalDist;
	FlatDist = sqrt(difx * difx + difz * difz);
	TotalDist = sqrt(FlatDist * FlatDist + dify * dify);

	// c. Y Rotation
	D3DXMatrixIdentity(&matRotateY);
	matRotateY._11 = matRotateY._33 = difz / FlatDist;    // cosY
	matRotateY._31 = difx / FlatDist;    // sinY
	matRotateY._13 = -matRotateY._31;    // -sinY

	// d. X Rotation
	D3DXMatrixIdentity(&matRotateX);
	matRotateX._22 = matRotateX._33 = FlatDist / TotalDist;    // cosX
	matRotateX._32 = dify / TotalDist;    // sinX
	matRotateX._23 = -matRotateX._32;    // -sinX

	// e. Tranlation
	static D3DXMATRIX matTranslate;
	D3DXMatrixTranslation(&matTranslate, position.x, position.y, position.z);

	// f. Scaling
	static D3DXMATRIX matScale;
	D3DXMatrixIdentity(&matScale);
	matScale._11 = matScale._22 = matScale._33 = radius;


	// Now build the world matrix and set it
	g_Render->GetDevice()->SetTransform(D3DTS_WORLD, &(matScale * matRotateX* matRotateY* matTranslate));

	return;
}

// this function renders the particle
void PARTICLE::render_particle()
{
	g_Render->GetDevice()->SetFVF(CUSTOMFVF);

	//set_particle(0.0f, 0.0f, 0.0f, 1.0f);

	g_Render->GetDevice()->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));

	g_Render->GetDevice()->SetTexture(0, texture);

	g_Render->GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

	return;
}

// this function updates the particle
void PARTICLE::run_particle(float seconds)
{
	velocity += acceleration * seconds;
	position += velocity * seconds;

	return;
}